package com.bosssoft.trainee.gateway.config;

import com.bosssoft.trainee.gateway.component.*;
import com.bosssoft.trainee.gateway.feign.GatewayFeign;
import com.bosssoft.trainee.gateway.filter.MyTokenFilter;
import com.bosssoft.trainee.security.config.IgnoreUrlsConfig;
import com.bosssoft.trainee.security.util.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsConfigurationSource;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import reactor.core.publisher.Mono;

/**
 * @Author: wuxin
 * @Project: rbac-SpringCloud
 * @Date: 2022/7/15
 * @Description:
 */
@Slf4j
@Configuration
@EnableWebFluxSecurity
public class GatewaySecurityConfig {
    @Lazy// 必须添加，不然会导致程序启动卡死
    @Autowired
    GatewayFeign gatewayFeign;

    @Autowired
    MyAuthorizationManager myAuthorizationManager;

    @Autowired
    MyAuthenticationManager myAuthenticationManager;

    @Autowired
    MySecurityContextRepository mySecurityContextRepository;


    @Bean
    public IgnoreUrlsConfig ignoreUrlsConfig() {
        log.info("SecurityConfig-添加忽略路径");
        return new IgnoreUrlsConfig();
    }

    @Bean
    public JwtTokenUtil jwtTokenUtil() {
        log.info("SecurityConfig-添加JwtToken工具");
        return new JwtTokenUtil();
    }

    @Bean
    SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        log.info("网络校验配置");
        //不需要保护的资源路径允许访问
        for (String url : ignoreUrlsConfig().getUrls()) {
            http.authorizeExchange().pathMatchers(url).permitAll();
        }
        //允许跨域请求的OPTIONS请求
        http.authorizeExchange()
                .pathMatchers(HttpMethod.OPTIONS).permitAll();
        http.authorizeExchange()
                // 任何请求需要身份认证
                .anyExchange().access(myAuthorizationManager) //权限
                // 自定义权限拒绝处理类
                .and().csrf().disable()
                .securityContextRepository(mySecurityContextRepository)//存储认证信息
                .authenticationManager(myAuthenticationManager) //认证管理
                .exceptionHandling()
                .accessDeniedHandler(new MyAccessDeniedHandler())
                .authenticationEntryPoint(new UnauthorizedEntryPoint())
                .and().cors().configurationSource(corsConfigurationSource());
        return http.build();
    }

    @Bean
    public ReactiveUserDetailsService reactiveUserDetailsService(){
        log.info("调用远程服务配置ReactiveUserDetailsService");
        return username -> Mono.just(gatewayFeign.loadUserByUsername(username));
    }


    public MyTokenFilter myTokenFilter() {
        log.info("SecurityConfig-添加JwtToken过滤器");
        return new MyTokenFilter();
    }
    private CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");    // 同源配置，*表示任何请求都视为同源，若需指定ip和端口可以改为如“localhost：8080”，多个以“，”分隔；
        corsConfiguration.addAllowedHeader("*");// header，允许哪些header，本案中使用的是token，此处可将*替换为token；
        corsConfiguration.addAllowedMethod("*");    // 允许的请求方法，PSOT、GET等
        source.registerCorsConfiguration("/**", corsConfiguration); // 配置允许跨域访问的url
        return source;
    }
}
